using System.IO;
using System.Linq;
using Framework.Core.Process;
using Framework.Core.Process.Tasks;

namespace Framework.Core.BootStrapper.Deployment
{
    internal class DeployPlugin : PluginBase<DeployPluginArgs>
    {
        internal interface IRemoteProcessControllerFactory
        {
            IProcessController Create(DeployPluginArgs args);
        }

        internal class RemoteProcessControllerFactory : IRemoteProcessControllerFactory
        {
            public IProcessController Create(DeployPluginArgs args)
            {
                return new RemoteProcessController(args.Machine, args.User, args.Password);
            }
        }


        private readonly IProcessController processController;
        private readonly IRemoteProcessControllerFactory remoteProcessControllerFactory;

        public DeployPlugin()
            : this(new ProcessController(), new RemoteProcessControllerFactory())
        {

        }

        internal DeployPlugin(IProcessController processController, IRemoteProcessControllerFactory remoteProcessControllerFactory)
        {
            this.processController = processController;
            this.remoteProcessControllerFactory = remoteProcessControllerFactory;
        }

        public override int Execute(DeployPluginArgs args)
        {
            var remoteProcessController = remoteProcessControllerFactory.Create(args);

            var executableDirectory = new DirectoryInfo(Path.GetDirectoryName(args.ExecutablePath));
            var zipPath = Path.Combine(executableDirectory.Parent.FullName, string.Format("{0}.zip", executableDirectory.Name));
            var zipName = Path.GetFileName(zipPath);

            CopyPackage(args, executableDirectory, zipPath, zipName);

            Deploy(args, remoteProcessController, zipName);

            return 0;
        }

        private static void Deploy(DeployPluginArgs args, IProcessController remoteProcessController, string zipName)
        {
            var killedProcesses = remoteProcessController.KillLocker(args.RemotePath);

            remoteProcessController.Start(new PsZip.PsZipExtract(string.Format(@"c:\windows\{0}", zipName), args.RemotePath));

            remoteProcessController.Start(new Command(Path.Combine(args.RemotePath, Path.GetFileName(args.ExecutablePath)), args.Arguments));

            killedProcesses.ToList().ForEach(kp => remoteProcessController.Start(kp));
        }

        private void CopyPackage(DeployPluginArgs args, FileSystemInfo executableDirectory, string zipPath, string zipName)
        {
            processController.Start(new PsZip.PsZipCompress(executableDirectory.FullName, zipPath));

            processController.Start(new Copy(zipPath, GetRemoteFileLocation(args, zipName)));
        }

        private static string GetRemoteFileLocation(DeployPluginArgs args, string zipName)
        {
            return string.Format(@"\\{0}\ADMIN$\{1}", args.Machine, Path.GetDirectoryName(zipName));
        }
    }
}